<script setup>
import axios from "axios";
import { onMounted } from "vue";
import ol from "@/utils/ol";
import Draw, { createRegularPolygon, createBox } from "ol/interaction/Draw";
import * as olProj from "ol/proj"; // 坐标变换使用
import { Fill, Stroke, Circle as CircleStyle, Style, Text } from "ol/style"; // 注意CircleStyle是样式
import Point from "ol/geom/Point";
import LineString from "ol/geom/LineString";
import geoCircle from "ol/geom/Circle"; // 注意geoCircle是圆形
import Polygon from "ol/geom/Polygon";
import GeometryCollection from "ol/geom/GeometryCollection";
import Feature from "ol/Feature";
import VectorLayer from "ol/layer/Vector";
import VectorSource from "ol/source/Vector";

import {
  getDrawSize,
  getScaleFactor,
  getRotateFactor,
  calculateCoords,
  getUnitSize,
  pathToCoords,
  circleToCoords,
  ellipseToCoords,
  polylineToCoords,
  polygonToCoords,
  rectToCoords,
  lineToCoords,
  textToCoords,
  parseItem,
  getTxtCPntAndWH,
  sleep,
  getMinMax,
} from "@/utils/vector";
import { plot } from "@comp/ol/plotting/plotting";
import mapconfig from "../../public/config/mapconfig.js";

let map, iDraw, plottingLayer;
const iActType = ref();
const iType = ref("None"); // 当前绘制的军标类型
const altNum = ref(0); // 控制点数量，用于控制点的计数及索引（查找时使用-添加控制点时递增；删除控制点时归零）
const iPlotSvgArr = ref([]); // 关联数组--保存所有调入的SVG数据（快速查找使用）
const plot_geometries = ref([]); // 临时生成对象[polygon,linestring,...] 临时绘制图形使用！？
const currPlot = ref({
  // 当前绘制军标的数据{id，svgname，center（cp），ctrlPointLS, color...} // 子组件为其提供信息--plotVector->parseSVG
  id: null,
  name: "", // 记录军标对应的svg文件
  cp: null, // ctrlPoint：中心点是cp[0],后边是控制点
  scale: null,
  rotate: null,
  color: "", // 绘制军标的颜色（六种）；类型确定？
  boxWH: null, // SVG文件屏幕坐标宽高
  unit: null,
  attach: null, // 附加字体数组
  style: null,
});
const svgCoords = ref([]); // 用来保存由svg解析出来的 元素和标点
const svgData = ref(); // 选择icon的svg数据（用于绘制）
const mapUnit = ref([500, 500]); // 单位为米 [1000, 1000]
const currColor = ref("#FF0000");
const FeatureParts = ref([]); // 绘制军标的组成部分{type: 'FeatureCollection',  features: [*****]}
const strokeWidth = ref(2); // 缺省军标线宽
const conf = ref(mapconfig); // 配置文件
const iUser = ref("master"); // 标绘用户
const plotFileID = ref(); // 当前标会的文件ID
const plotRecord = ref({}); // 标绘动作记录--关联改对象；Object.keys(p l o t Record).length
const recordLen = ref(3); // 标绘动作记录数组长度
const isSave = ref(false); // 保存状态标志位
const xData = ref([]); // 记录每个所绘军标元素的基本信息，currPlot数据格式
const iconGroupJSON = ref({}); // 图标分组原始数据
const drawing = ref({
  地图信息: {
    军标信息: { data: [] },
    行政区划信息: [],
    自定义边界坐标: [],
  },
  文字: {
    显示: false,
    边框: false,
    标题位置: "",
    内容: "",
    文字大小: 36,
    字体: "",
    位置: "",
  },
  图例: {
    显示: "",
    位置: "",
    内容: [],
  },
  直角坐标系: false,
  边框: false,
  比例尺: {},
  指南针: {
    显示: false,
    位置: "右上",
  },
  历史图标: [],
});
const bbox = ref(); // 范围盒
const alterPlot = ref(); // 要修改的军标数据，和currPlot结构一致

const initMap = () => {
  const tk = "fb854e7c9218a0d4903e4c765df3fa63";
  const baseLayer = new ol.layer.Tile({
    source: new ol.source.XYZ({
      maxZoom: 18,
      url: `http://t4.tianditu.com/DataServer?T=vec_w&tk=${tk}&x={x}&y={y}&l={z}`,
      crossOrigin: "anonymous",
    }),
    name: "矢量地图",
  });
  const zjLayer = new ol.layer.Tile({
    source: new ol.source.XYZ({
      maxZoom: 18,
      url: `http://t4.tianditu.com/DataServer?T=cva_w&tk=${tk}&x={x}&y={y}&l={z}`,
      crossOrigin: "anonymous",
    }),
    name: "矢量注记",
  });
  map = new ol.Map({
    view: new ol.View({
      projection: "EPSG:4326",
      center: [121.43, 37.45],
      zoom: 10,
    }),
    layers: [baseLayer, zjLayer],
    target: "map",
  });
  window.map = map;
};

const lineClick = () => {
  const obj = {
    key: "dire_bm_lxhlfsq030308",
    label: "封锁区",
    方法: "是",
  };
  selectPlot(obj.key);
};

const selectPlot = (plotID) => {
  // 如果调用的军标ID和之前一样，直接绘制
  if (iActType.value === plotID) {
    // 调用开始绘制
    beginPlotting(plotID);
  } else {
    // 否则需要重新调用军标（异步需要等待！）
    iActType.value = plotID;
    getPlotData(plotID); // 调用军标数据；// 调用plottinglayer方法，其内部使用vec的get-PlotDataEx方法
    setPlotType(plotID); // 修改plottingLayer.iType;触发draw事件绘制
  }
};

/*
 * 开始本次军标绘制-选择军标类型开始绘制
 */
const beginPlotting = (plotID) => {
  clearCtrlPoint();
  iType.value = plotID;
  iTypeWatch();
};
// 结束本次军标绘制，等待新的开始
const endPlotting = () => {
  iType.value = null;
  iTypeWatch();
};

// 删除控制点
const clearCtrlPoint = () => {
  if (plottingLayer) return;
  const xSource = plottingLayer.getSource();
  xSource.getFeatures().forEach(function (feature) {
    const xID = feature.get("gid").substr(0, 3);
    if (xID === "alt") {
      xSource.removeFeature(feature);
    }
  });
  // 计数器归零
  altNum.value = 0;
};

/**
 * @description 选择绘制的（军标），读入军标数据；调用plotVector的get-PlotDataEx方法（新）
 * @param sPlotID {String}军标ID（名称）  async
 * @return 无
 */
const getPlotData = (plotID) => {
  // 筛选
  if (plotID.length < 4) return;
  const iType = plotID.substr(0, 4);
  switch (iType) {
    case "icon":
      getSVGDataByID(plotID, iPlotSvgArr.value);
      break;
    case "dire":
    case "ddir":
      getSVGDataByID(plotID, iPlotSvgArr.value);
      break;
    case "mult":
      break;
    default:
  }
};
// 根据军标名称获取SVG数据- （将数据写入vertor的svgSata中；返回SVG数据）
const getSVGDataByID = async (plotID, iPlotSvgArr) => {
  const plotSVG = iPlotSvgArr?.[plotID] || "";
  if (plotSVG) {
    svgData.value = plotSVG;
  } else {
    svgData.value = await getPlotDataEx(plotID);
    // 保存到军标数组中
    iPlotSvgArr.value[plotID] = svgData.value;
  }
};

const getPlotDataEx = (plotID) => {
  return new Promise(function (resolve) {
    axios.get("/mapres/plot/used/" + plotID + ".svg").then((res) => {
      resolve(res);
    });
  });
};
/* Method: setPlotType
 * 设置军标类型
 * 参数 pType：军标类型或军标ID
 * 返回：
 */
const setPlotType = (pType) => {
  iType.value = pType;
  iTypeWatch();
};

const iTypeWatch = () => {
  if (
    iType.value === "plottModify" ||
    iType.value === "plottMove" ||
    iType.value === "plottDel"
  ) {
  } else {
    if (iType.value) {
      map.removeInteraction(iDraw);
      addInteraction();
    } else {
      map.removeInteraction(iDraw);
    }
  }
};

/* Method：parseSVG(输入单个控制点模式)
 * 分析SVG数据，将个元素转换成屏幕坐标；范围在鼠标绘制区域
 * 参数：drawPointLs点坐标信息，typeId军标ID
 * 返回：新生成的图形屏幕坐标
 */
const parseSVG = (drawPointLs, typeId) => {
  let SCALE = 1; // 缩放因子,调用方法自动计算比率取得此因子--待
  let ROTATE = 0; // 旋转角度
  const NUM_POINTS = 50; // 路径分段数量
  const chkArr = ["CP", "TL", "TM", "TR", "LM", "RM", "BL", "BM", "BR"]; // 校验数据；验证basePoint是否有效
  let basePoint = "CP"; // [tl,tm,tr,lm,rm,bl,bm,br,cp中心点] // 圆点的位置说明--注意：大写
  let coordinates = null;

  // 清空svgCoords--保存所有构成SVG的点（屏幕坐标）
  svgCoords.value.splice(0, svgCoords.value.length);
  // 绘制点有效性检查
  if (!drawPointLs) return;
  // 根据文件名称获取处理信息; 文件名格式：icon_BM_110201.svg
  const paramArr = typeId.split("_");
  if (paramArr.length > 2) {
    // 有三个以上元素时，使用第二个元素为中心点；出现多于元素--编号中有“下划线”
    basePoint = paramArr[1].toUpperCase();
  } else if (paramArr.length === 2) {
    // 文件名称中不包含中心点位置；使用默认值CP
    basePoint = "CP";
  } else if (paramArr.length === 1) {
    // 只有一个文件名称是，使用CP；经过上层筛选，不可能出现！
    basePoint = "CP";
  } else {
    // 没有数据时返回
    return;
  }
  // basePoint校验
  if (chkArr.indexOf(basePoint) === -1) {
    basePoint = "CP";
  }

  // 鼠标绘制的有个点，为中心点（不同类型，可能中心位置不用，圆是中心，旗子是左下角-插旗点）
  const cp = drawPointLs[0];
  // 创建一个元素容器，用来添加svg数据
  const empty = document.createElement("div");
  empty.innerHTML = svgData.value.data;
  // 获取svg内容数据
  const svgRoot = empty.querySelector("svg");
  if (drawPointLs.length > 1) {
    // 获取鼠标绘制点框选大小（默认首个点是中心点 返回{ width: w, height: h }）
    const WH = getDrawSize(drawPointLs);
    // 获取比例因子(x方向和y方向比较大的一个)
    SCALE = getScaleFactor(WH, svgRoot); // empty.querySelector('svg')
    ROTATE = getRotateFactor(drawPointLs);
    coordinates = calculateCoords(cp, svgRoot, SCALE, basePoint); // empty.querySelector('svg')
  } else {
    //
    // 将svg数据提取出来计算，调用calculateCoords进行处理--计算左上角坐标
    const WH = getUnitSize(drawPointLs, basePoint, mapUnit.vue); // 根据给定尺寸（米），设置军标尺寸：默认左右各1000
    SCALE = getScaleFactor(WH, svgRoot);
    ROTATE = getRotateFactor(drawPointLs);
    coordinates = calculateCoords(cp, svgRoot, SCALE, basePoint); // empty.querySelector('svg')
  }
  // 将信息回馈给父组件
  const ctrlPnt = drawPointLs.map((d) => {
    // 转换成地理坐标（根据投影获取返回的坐标：如果不是3857而是4490后续可能有问题）
    const c = map.getCoordinateFromPixel(d); // 4490返回的是经纬度[116.08994635036495, 40.28763959854017]
    return [c[0], c[1]];
  });
  currPlot.value.name = typeId; // svg文件名称
  currPlot.value.cp = ctrlPnt; // drawPointLs -- ctrlpoint控制点，包含中心点
  currPlot.value.scale = SCALE;
  currPlot.value.rotate = ROTATE;
  currPlot.value.color = currColor.value; // 颜色
  currPlot.value.boxWH = null; // 暂时不支持SVG
  currPlot.value.unit = mapUnit.vue;
  currPlot.value.attach = null;
  for (let i = 0; i < svgRoot.childNodes.length; i++) {
    const tName = svgRoot.childNodes[i].tagName;
    switch (tName) {
      case "path": // 处理数据路径数据
        pathToCoords(
          svgRoot.childNodes[i],
          SCALE, // 缩放SCALE 1
          NUM_POINTS, // NUM_POINTS 路径分成点数；不同类型不同数量  ?20
          coordinates.x,
          coordinates.y,
          cp,
          ROTATE,
          ({ path, coords }) => {
            svgCoords.value.push({ path, coords });
          }
        );

        break;
      case "circle": // 处理圆形数据
        circleToCoords(
          svgRoot.childNodes[i],
          SCALE, // 缩放SCALE 1
          NUM_POINTS, // NUM_POINTS 路径分成点数；圆18个点
          coordinates.x,
          coordinates.y,
          cp,
          ROTATE,
          ({ path, coords }) => {
            svgCoords.value.push({ path, coords });
          }
        );
        break;
      case "ellipse": // 处理椭圆数据
        ellipseToCoords(
          svgRoot.childNodes[i],
          SCALE, // 缩放SCALE 1
          NUM_POINTS, // NUM_POINTS 路径分成点数；圆18个点
          coordinates.x,
          coordinates.y,
          cp,
          ROTATE,
          ({ path, coords }) => {
            svgCoords.value.push({ path, coords });
          }
        );
        break;
      case "polyline": // 处理多边形线数据
        polylineToCoords(
          svgRoot.childNodes[i],
          SCALE, // 缩放SCALE 1
          coordinates.x,
          coordinates.y,
          cp,
          ROTATE,
          ({ path, coords }) => {
            svgCoords.value.push({ path, coords });
          }
        );
        break;
      case "polygon": // 处理多边形数据
        polygonToCoords(
          svgRoot.childNodes[i],
          SCALE, // 缩放SCALE 1
          coordinates.x,
          coordinates.y,
          cp,
          ROTATE,
          ({ path, coords }) => {
            svgCoords.value.push({ path, coords });
          }
        );
        break;
      case "rect": // 处理矩形数据
        rectToCoords(
          svgRoot.childNodes[i],
          SCALE, // 缩放SCALE 1
          coordinates.x,
          coordinates.y,
          cp,
          ROTATE,
          ({ path, coords }) => {
            svgCoords.value.push({ path, coords });
          }
        );
        break;
      case "line": // 处理线段数据
        lineToCoords(
          svgRoot.childNodes[i],
          SCALE, // 缩放SCALE 1
          coordinates.x,
          coordinates.y,
          cp,
          ROTATE,
          ({ path, coords }) => {
            svgCoords.value.push({ path, coords });
          }
        );
        break;
      case "text": // 处理文字数据
        textToCoords(
          svgRoot.childNodes[i],
          SCALE,
          coordinates.x,
          coordinates.y,
          cp,
          ROTATE,
          ({ path, coords }) => {
            svgCoords.value.push({ path, coords });
          }
        );
        break;
      case "g": // 处理组数据
        parseItem(
          svgRoot.childNodes[i],
          coordinates.x,
          coordinates.y,
          cp,
          SCALE,
          ROTATE,
          NUM_POINTS,
          ({ path, coords }) => {
            svgCoords.value.push({ path, coords });
          }
        );
        break;
    }
  }
};

/* Method：getSecondCoord 注：需要使用地理坐标，注意调用位置！
 * 提供给icon军标获取第二个控制点坐标，根据基本点生成; ['CP', 'TL', 'TM', 'TR', 'LM', 'RM', 'BL', 'BM', 'BR']
 * 参数：iconPlot-当前绘制的军标数据信息
 */
const getSecondCoord = (iconPlot) => {
  if (!iconPlot) return;
  const chkArr = ["CP", "TL", "TM", "TR", "LM", "RM", "BL", "BM", "BR"]; // 校验数据；验证basePoint是否有效
  const iPlotID = iconPlot.name;
  let cp = iconPlot.cp[0];
  const geoUnit = iconPlot.unit;
  let basePoint = null;
  const paramArr = iPlotID.split("_"); // 将icon军标的名称分解成数组[icon，cp，plotCode]
  if (paramArr.length > 2) {
    // 有三个以上元素时，使用第二个元素为中心点；出现多于元素--编号中有“下划线”
    basePoint = paramArr[1].toUpperCase();
  } else if (paramArr.length === 2) {
    // 文件名称中不包含中心点位置；使用默认值CP
    basePoint = "CP";
  } else if (paramArr.length === 1) {
    // 只有一个文件名称是，使用CP
    basePoint = "CP";
  } else {
    // 没有数据时返回
    return;
  }
  // basePoint校验
  if (chkArr.indexOf(basePoint) === -1) {
    basePoint = "CP";
  }

  // 这里的cp是需要epsg3857的，否则不能通过下面方式计算另一个控制点
  const sRCS = map.getView().getProjection().getCode();
  if (sRCS !== "EPSG:3857") {
    cp = olProj.transform(cp, sRCS, "EPSG:3857");
  }
  let secPnt;
  switch (basePoint) {
    case "CP":
      // 中心对应的控制点是左下角
      secPnt = [cp[0] + geoUnit[0] * 2, cp[1] - geoUnit[1] * 2];
      break;
    case "TL":
      secPnt = [cp[0] + geoUnit[0] * 2, cp[1] - geoUnit[1] * 2];
      break;
    case "TM":
      secPnt = [cp[0], cp[1] - geoUnit[1] * 2];
      break;
    case "TR":
      secPnt = [cp[0] - geoUnit[0] * 2, cp[1] - geoUnit[1] * 2];
      break;
    case "LM":
      secPnt = [cp[0] + geoUnit[0] * 2, cp[1]];
      break;
    case "RM":
      secPnt = [cp[0] - geoUnit[0] * 2, cp[1]];
      break;
    case "BL":
      secPnt = [cp[0] + geoUnit[0] * 2, cp[1] + geoUnit[1] * 2];
      break;
    case "BM":
      secPnt = [cp[0], cp[1] + geoUnit[1] * 2];
      break;
    case "BR":
      secPnt = [cp[0] - geoUnit[0] * 2, cp[1] + geoUnit[1] * 2];
      break;
    default:
      secPnt = [cp[0] + geoUnit[0], cp[1] + geoUnit[1]];
  }
  if (sRCS !== "EPSG:3857") {
    secPnt = olProj.transform(secPnt, "EPSG:3857", sRCS);
  }
  // 返回生成的第二个控制点坐标
  return {
    x: secPnt[0],
    y: secPnt[1],
  };
};

// 添加文字旋转信息
const buildGeom = (gID, data = svgCoords.value) => {
  const geodata = []; // 保存生成的每个图元元素
  // 清空之前的this.FeatureParts数据（删除原来绘制的军标）
  if (FeatureParts.value instanceof Array) {
    FeatureParts.value.splice(0, FeatureParts.value.length);
  }
  if (data.length < 1) return; // 没有数据时不做处理
  // 循环处理所有解析的数据
  for (let i = 0; i < data.length; i++) {
    // data数据包含 {svg的path-原数据，和path上取得坐标}
    const { path, coords } = data[i];
    // 需要区分当前处理数据类型；文字需要特殊处理
    const dataType = path.tagName;
    // 生成文字处理数据
    if (dataType === "text") {
      const iText = path.innerHTML;
      const d = coords[0];
      const txtRot = coords[1][1]; // 文本的坐标中[[文字坐标x，y]，[scale，rotate]]
      const geomData = [];
      const c = map.getCoordinateFromPixel(d);
      geomData.push(c);
      geomData.push(coords[1]);
      // 字体样式样式设置
      const iFont = path.getAttribute("font-family");
      const iSize = path.getAttribute("font-size");
      let pFont = "normal ";
      if (iSize) {
        pFont = pFont + iSize + "px ";
      } else {
        pFont = pFont + "14px ";
      }
      if (iFont) {
        pFont = pFont + iFont;
      } else {
        pFont = pFont + "微软雅黑";
      }
      const iStyle = {
        txt: iText,
        font: pFont,
        fill: "#000",
        rotate: txtRot,
        stroke: null,
        width: 0,
      };
      geodata.push({
        gid: gID,
        type: "Point",
        data: geomData,
        style: iStyle,
      });
    } else {
      // 如果第一个和最后一个坐标一致，视为闭口多边形;没有填充色时，视为多边形线LineString
      if (
        coords[0][0] === coords[coords.length - 1][0] &&
        coords[0][1] === coords[coords.length - 1][1]
      ) {
        // 将屏幕坐标转换为地理坐标
        const geomData = coords.map((d) => {
          // 本模块作为功能模块，不保存map对象，直接调用父组件map
          const c = map.getCoordinateFromPixel(d);
          return [c[0], c[1]];
        });
        const iStyle = {
          fill: svgCoords.value[i].path.getAttribute("fill"),
          stroke: svgCoords.value[i].path.getAttribute("stroke"),
          width: svgCoords.value[i].path.getAttribute("stroke-width"),
        };
        geodata.push({
          gid: gID,
          type: "polygon",
          data: [geomData],
          style: iStyle,
        });
      } else {
        // 屏幕坐标转换为地理坐标
        const geomData = coords.map((d) => {
          // 本模块作为功能模块，不保存map对象，直接调用父组件map
          const c = map.getCoordinateFromPixel(d);
          return [c[0], c[1]];
        });
        // console.log(geomData)
        // 获取样式
        const iStyle = {
          fill: svgCoords.value[i].path.getAttribute("fill"),
          stroke: svgCoords.value[i].path.getAttribute("stroke"),
          width: svgCoords.value[i].path.getAttribute("stroke-width"),
        };
        geodata.push({
          gid: gID,
          type: "linestring",
          data: geomData,
          style: iStyle,
        });
      }
    }
    FeatureParts.value = { geoType: "GeometryCollection", geoData: geodata };
  }
};

// 绘制需要重新计算scale！替换updatePlot方法
// 参数 drawPointLs: 军标控制点数组; typeID:军标的ID(用来获取质心)；enableRotate：是否启用旋转（icon不使用旋转）
const updateSVGPlot = (drawPointLs, typeId, enableRotate = true) => {
  let SCALE = 1; // 缩放因子,调用方法自动计算比率取得此因子--待
  let ROTATE = 0; // 旋转角度
  const NUM_POINTS = 50; // 路径分段数量
  const chkArr = ["CP", "TL", "TM", "TR", "LM", "RM", "BL", "BM", "BR"]; // 校验数据；验证basePoint是否有效
  let basePoint = "CP"; // [tl,tm,tr,lm,rm,bl,bm,br,cp中心点] // 圆点的位置说明--注意：大写
  let coordinates = null;

  // 清空svgCoords--保存所有构成SVG的点（屏幕坐标）
  svgCoords.value.splice(0, svgCoords.value.length);
  // 绘制点有效性检查
  if (!drawPointLs) return;
  // 根据文件名称获取处理信息; 文件名格式：icon_BM_110201.svg
  const paramArr = typeId.split("_");
  if (paramArr.length > 2) {
    // 有三个以上元素时，使用第二个元素为中心点；出现多于元素--编号中有“下划线”
    basePoint = paramArr[1].toUpperCase();
  } else if (paramArr.length === 2) {
    // 文件名称中不包含中心点位置；使用默认值CP
    basePoint = "CP";
  } else if (paramArr.length === 1) {
    // 只有一个文件名称是，使用CP；经过上层筛选，不可能出现！
    basePoint = "CP";
  } else {
    // 没有数据时返回
    return;
  }
  // basePoint校验
  if (chkArr.indexOf(basePoint) === -1) {
    basePoint = "CP";
  }

  // 鼠标绘制的有个点，为中心点（不同类型，可能中心位置不用，圆是中心，旗子是左下角-插旗点）
  const cp = drawPointLs[0];
  // 创建一个元素容器，用来添加svg数据
  const empty = document.createElement("div");
  empty.innerHTML = svgData.value.data;
  // 获取svg内容数据
  const svgRoot = empty.querySelector("svg");
  if (drawPointLs.length > 1) {
    // 获取鼠标绘制点框选大小（默认首个点是中心点 返回{ width: w, height: h }）
    const WH = getDrawSize(drawPointLs);
    // 获取比例因子(x方向和y方向比较大的一个)
    SCALE = getScaleFactor(WH, svgRoot); // empty.querySelector('svg')
    // 如果启用旋转，计算旋转因子；
    if (enableRotate) {
      ROTATE = getRotateFactor(drawPointLs);
    }
    coordinates = calculateCoords(cp, svgRoot, SCALE, basePoint); // empty.querySelector('svg')
  } else {
    //
    // 将svg数据提取出来计算，调用calculateCoords进行处理--计算左上角坐标
    const WH = getUnitSize(drawPointLs, basePoint, this.mapUnit); // 根据给定尺寸（米），设置军标尺寸：默认左右各1000
    SCALE = getScaleFactor(WH, svgRoot);
    coordinates = calculateCoords(cp, svgRoot, SCALE, basePoint); // empty.querySelector('svg')
  }
  // 分析数据
  for (let i = 0; i < svgRoot.childNodes.length; i++) {
    const tName = svgRoot.childNodes[i].tagName;
    switch (tName) {
      case "path": // 处理数据路径数据
        pathToCoords(
          svgRoot.childNodes[i],
          SCALE, // 缩放SCALE 1
          NUM_POINTS, // NUM_POINTS 路径分成点数；不同类型不同数量  ?20
          coordinates.x,
          coordinates.y,
          cp,
          ROTATE,
          (obj) => {
            svgCoords.value.push({ path, coords });
          }
        );
        break;
      case "circle": // 处理圆形数据
        circleToCoords(
          svgRoot.childNodes[i],
          SCALE, // 缩放SCALE 1
          NUM_POINTS, // NUM_POINTS 路径分成点数；圆18个点
          coordinates.x,
          coordinates.y,
          cp,
          ROTATE,
          (obj) => {
            svgCoords.value.push({ path, coords });
          }
        );
        break;
      case "ellipse": // 处理椭圆数据
        ellipseToCoords(
          svgRoot.childNodes[i],
          SCALE, // 缩放SCALE 1
          NUM_POINTS, // NUM_POINTS 路径分成点数；圆18个点
          coordinates.x,
          coordinates.y,
          cp,
          ROTATE,
          (obj) => {
            svgCoords.value.push({ path, coords });
          }
        );
        break;
      case "polyline": // 处理多边形线数据
        polylineToCoords(
          svgRoot.childNodes[i],
          SCALE, // 缩放SCALE 1
          coordinates.x,
          coordinates.y,
          cp,
          ROTATE,
          (obj) => {
            svgCoords.value.push({ path, coords });
          }
        );
        break;
      case "polygon": // 处理多边形数据
        polygonToCoords(
          svgRoot.childNodes[i],
          SCALE, // 缩放SCALE 1
          coordinates.x,
          coordinates.y,
          cp,
          ROTATE,
          (obj) => {
            svgCoords.value.push({ path, coords });
          }
        );
        break;
      case "rect": // 处理矩形数据
        rectToCoords(
          svgRoot.childNodes[i],
          SCALE, // 缩放SCALE 1
          coordinates.x,
          coordinates.y,
          cp,
          ROTATE,
          (obj) => {
            svgCoords.value.push({ path, coords });
          }
        );
        break;
      case "line": // 处理线段数据
        lineToCoords(
          svgRoot.childNodes[i],
          SCALE, // 缩放SCALE 1
          coordinates.x,
          coordinates.y,
          cp,
          ROTATE,
          (obj) => {
            svgCoords.value.push({ path, coords });
          }
        );
        break;
      case "text": // 处理文字数据
        this.textToCoords(
          svgRoot.childNodes[i],
          SCALE,
          coordinates.x,
          coordinates.y,
          cp,
          ROTATE,
          (obj) => {
            svgCoords.value.push({ path, coords });
          }
        );
        break;
      case "g": // 处理组数据
        this.parseItem(
          svgRoot.childNodes[i],
          coordinates.x,
          coordinates.y,
          cp,
          SCALE,
          ROTATE,
          NUM_POINTS,
          (obj) => {
            svgCoords.value.push({ path, coords });
          }
        );
        break;
    }
  }
};

/* Method：createSVGPlot
 * 根据SVG军标数据生成军标
 * 参数：plotData军标信息
 * 返回：drawPointLs点坐标信息，drawType绘制军标类型，typeId军标ID（矢量svg_id），地图iMap
 */
const pVecCreateSVGPlot = (plotData) => {
  const tID = plotData.id; // 组ID
  const drawType = tID.substr(0, 4); // 军标类型
  // 这里使用屏幕坐标绘制
  const ctrlPnt = plotData.cp.map((d) => {
    // 转换成屏幕坐标
    const c = map.getPixelFromCoordinate(d);
    return [c[0], c[1]];
  });

  switch (drawType) {
    case "icon":
      // 调用绘制固定图标
      updateSVGPlot(ctrlPnt, plotData.name, false);
      buildGeom(tID); // 数据格式{geoType:xx,geoData[{gid,type,data,style}{gid,type,data,style}]
      break;
    // 有方向军标
    case "dire":
    case "ddir":
      // 调用绘制固定图标
      updateSVGPlot(ctrlPnt, plotData.name);
      buildGeom(tID); // 数据格式{geoType:xx,geoData[{gid,type,data,style}{gid,type,data,style}]
      break;
    default:
      console.log("other");
  }
  return FeatureParts.value; // 返回新建的对象列表
};

// 创建SVG军标
const createSVGPlot = async (plotData = alterPlot.value) => {
  // 首先根据军标名称调用对应的SVG
  // 如果SVG没有变更不需要重新调入
  if (iType.value !== plotData.name) {
    // 调用军标绘制所需要的SVG -- 可能需要延时处理
    getPlotData(plotData.name); // 调用自己的加载数据方法，使用vec的get-PlotDataEx方法
    await sleep(200); // 不添加等待会有闪烁（切换）
  }
  if (plotData.name.substr(0, 4) === "ddir") {
    getPlotData(plotData.name); // 调用自己的加载数据方法，使用vec的get-PlotDataEx方法
    await sleep(200); // 不添加等待会有闪烁（切换）
  }
  // 需要更新旋转和缩放因子--注意CardMap中已经更新；控制点需要使用屏幕坐标
  plot_geometries.value = pVecCreateSVGPlot(plotData);
  setSVGStyle(plot_geometries.value, strokeWidth.value, plotData.color);
  geom2Featrue(plot_geometries.value);
};

/* Method：getFeature
 * 绘制军标，得到相应的feature坐标点；总的绘制接口点（main）
 * 参数：drawPointLs点坐标信息，drawType绘制军标类型，typeId军标ID（矢量svg_id），地图iMap
 * 返回：
 */
const getFeature = (drawPointLs, drawType, typeId, iMap) => {
  // 这里的drawPointLs是鼠标点击地图所获得的坐标（转成的屏幕坐标）
  let tID = null;
  // 屏幕坐标列表，保存通过绘制点计算得来的svg
  let secPoint = null;
  switch (drawType) {
    case "icon":
      // 调用绘制固定图标
      parseSVG(drawPointLs, typeId); // 解析svg数据，将数据写入到svgCoords中，以便下面生成Feature
      // 获取时间标签
      tID = "icon_" + String(new Date().getTime());
      currPlot.value.id = tID; // 更新当前军标的组ID
      buildGeom(tID); // 数据格式{geoType:xx,geoData[{gid,type,data,style}{gid,type,data,style}]
      // 获取icon的第二控制点;注意要使用地理坐标！，所以在buildGeom将屏幕坐标转换成地理坐标后使用--可能需要添加坐标转换
      secPoint = getSecondCoord(currPlot.value); // 返回对象{x:123, y:456}
      currPlot.value.cp.push([secPoint.x, secPoint.y]);
      break;
    // 有方向军标
    case "dire":
      // 调用绘制方向图标
      // 由两点控制大小与方向--生成数据写入到this.svgCoords
      parseSVG(drawPointLs, typeId); // 解析svg数据，将数据写入到svgCoords中，以便下面生成Feature
      tID = "dire_" + String(new Date().getTime()); // 获取时间标签
      currPlot.value.id = tID; // 更新当前军标的组ID
      // 数据格式{geoType:xx,geoData[{gid,type,data,style}{gid,type,data,style}]
      buildGeom(tID);
      break;
    case "ddir":
      // 调用绘制方向图标
      // 由两点控制大小与方向--生成数据写入到this.svgCoords
      parseSVG(drawPointLs, typeId); // 解析svg数据，将数据写入到svgCoords中，以便下面生成Feature
      tID = "ddir_" + String(new Date().getTime()); // 获取时间标签
      currPlot.value.id = tID; // 更新当前军标的组ID
      // 数据格式{geoType:xx,geoData[{gid,type,data,style}{gid,type,data,style}]
      buildGeom(tID);
      break;
    default:
      console.log("other");
  }
  return FeatureParts.value; // 返回新建的对象列表
};

// 添加color
const setSVGStyle = (iPlotParts, StrokeW, iColor) => {
  const len = iPlotParts.geoData.length;
  let maxWidth = 0;
  // 循环每个组成部件，查找最大线宽度值；point类型排除在外
  for (let i = 0; i < len; i++) {
    const xPart = iPlotParts.geoData[i];
    if (xPart.type.toLowerCase() !== "point") {
      const w = xPart.style.width;
      if (w) {
        if (w > maxWidth) {
          maxWidth = w;
        }
      }
    }
  } // 查找最大线宽度值-结束
  for (let i = 0; i < len; i++) {
    const xPart = iPlotParts.geoData[i];
    if (xPart.type.toLowerCase() !== "point") {
      const w = xPart.style.width;
      if (w) {
        // 如果w非null
        if (w === maxWidth) {
          plot_geometries.value.geoData[i].style.width = StrokeW;
        } else {
          plot_geometries.value.geoData[i].style.width =
            (w / maxWidth) * StrokeW;
        }
      } // 线宽设置结束

      // 军标主颜色设置
      const xFill = xPart.style.fill;
      const xStroke = xPart.style.stroke;
      if (
        xFill &&
        xFill !== "none" &&
        xFill !== "#003F98" &&
        xFill !== "#FFF000" &&
        xFill !== "#009944" &&
        xFill !== "#004097" &&
        xFill !== "#ffffff" &&
        xFill !== "#000000" &&
        xFill !== "#FF0000" &&
        xFill !== "#0000FF" &&
        xFill !== "#00FF00" &&
        xFill !== "#FF60AF"
      ) {
        plot_geometries.value.geoData[i].style.fill = iColor;
      }
      if (
        xStroke &&
        xStroke !== "none" &&
        xStroke !== "#003F98" &&
        xStroke !== "#FFF000" &&
        xStroke !== "#009944" &&
        xStroke !== "#004097" &&
        xStroke !== "#FF0000" &&
        xStroke !== "#0000FF" &&
        xStroke !== "#00FF00" &&
        xStroke !== "#FF60AF"
      ) {
        plot_geometries.value.geoData[i].style.stroke = iColor;
      }
    }
  }
};

// 设置样式;参数 Fill填充色或文字颜色； Stroke边色； Width边框； LineDash虚线样式； TEXT文本内容； Font字体样式，如： ‘normal 12px 微软雅黑’
const setCurrPlotStyle = (
  Fill = "none",
  Stroke = null,
  Width = 0,
  LineDash = null,
  TEXT = null,
  Font = null
) => {
  let iStyle = null;
  // 有虚线设置
  if (LineDash) {
    // 有文字，有虚线--（一般不会出现）
    if (TEXT) {
      iStyle = {
        fill: Fill,
        stroke: Stroke,
        width: Width,
        lineDash: LineDash,
        text: TEXT,
        font: Font,
      };
    } else {
      // 无文字，有虚线； --（绘制虚线）
      iStyle = {
        fill: Fill,
        stroke: Stroke,
        width: Width,
        lineDash: LineDash,
      };
    }
  } else {
    // 无虚线设置
    // 有文字，无虚线--（书写文字）
    if (TEXT) {
      iStyle = {
        fill: Fill,
        stroke: Stroke,
        width: Width,
        text: TEXT,
        font: Font,
      };
    } else {
      // 无文字，无虚线--（普通形状）
      iStyle = {
        fill: Fill,
        stroke: Stroke,
        width: Width,
      };
    }
  }
  // 写入样式
  currPlot.value.style = JSON.parse(JSON.stringify(iStyle));
};

/*
 * Method：geom2Featrue
 * 将从getFeature获得的数据{geoType:x.geoData:[{gid,type,data,style},{},...]}添加到标绘层
 * 参数：gData：{geoType:x.geoData:[{gid,type,data,style},{},...]}
 */
// 带文字旋转 参数：sSRS表示数据的坐标格式（所有标绘操作都已'EPSG:3857'为准）
const geom2Featrue = (plotData = plot_geometries.value, sSRS = "EPSG:3857") => {
  if (!plotData) return;
  const sRCS = conf.value.RCS; // 地图的坐标系名称{String}
  const gType = plotData.geoType;
  const gData = plotData.geoData;
  let iGeom = null;
  let iFeature = null;
  if (gType === "GeometryCollection") {
    for (let i = 0; i < gData.length; i++) {
      const gID = gData[i].gid;
      let iType = gData[i].type;
      const iData = gData[i].data;
      const iStyle = gData[i].style;
      let newStyle = null;
      iType = iType.toLowerCase();
      // 处理多边形
      if (iType === "polygon") {
        iGeom = new Polygon(iData);
        iFeature = new Feature(iGeom);
        iFeature.set("gid", gID);
        iFeature.set("type", "PLOT");
        // 属性创建
        if (iStyle.fill === "none" || !iStyle.fill) {
          // 没有填充颜色-1
          let strokeColor = iStyle.stroke;
          if (!strokeColor) {
            // 勾边色为空，设置为当前色
            strokeColor = currColor.value;
          }
          // 有勾边色，设置多边形为描边样式，边的颜色如果不是固有色，替换成当前色： B-1
          if (
            strokeColor &&
            strokeColor !== "#003F98" &&
            strokeColor !== "#FFF000" &&
            strokeColor !== "#009944" &&
            strokeColor !== "#004097" &&
            strokeColor !== "#FF0000" &&
            strokeColor !== "#0000FF" &&
            strokeColor !== "#00FF00" &&
            strokeColor !== "#FF60AF"
          ) {
            // 有描边色
            newStyle = new Style({
              fill: new Fill({
                color: "rgba(0,0,0,0)",
              }),
              stroke: new Stroke({
                color: currColor.value,
                width: iStyle.width ? iStyle.width : 0,
              }),
            });
          } else if (
            strokeColor === "#003F98" ||
            strokeColor === "#FFF000" ||
            strokeColor === "#009944" ||
            strokeColor === "#004097" ||
            strokeColor === "#FF0000" ||
            strokeColor === "#0000FF" ||
            strokeColor === "#00FF00" ||
            strokeColor === "#FF60AF"
          ) {
            // B-2 勾边为固有色，勾边色保持不变！
            newStyle = new Style({
              fill: new Fill({
                color: "rgba(0,0,0,0)",
              }),
              stroke: new Stroke({
                color: strokeColor,
                width: iStyle.width ? iStyle.width : 0,
              }),
            });
          }
          // iFeature.setStyle(iStyle)
          // 样式数据写入当前绘制军标数据中（currPlot）-- icon和dire及mult方式只需要颜色就可以了，不需要使用样式！
          // 原型 setCurrPlot (ID, plotName = proxy.iType, ctrlPoint = null, SCALE = 1, ROTATE = 0, COLOR = currColor.value, UNIT = null, STYLE = null)
          // 原型 setCurrPlotStyle (Fill = 'none', Stroke = null, Width = 0, LineDash = null, TEXT = null, Font = null) getText
          currPlot.value.style = null;
        } else {
          // 多边形有填充色-2
          // 多边形有填充色，非固有色。使用当前颜色2-1
          if (
            iStyle.fill !== "#003F98" &&
            iStyle.fill !== "#FFF000" &&
            iStyle.fill !== "#009944" &&
            iStyle.fill !== "#004097" &&
            iStyle.fill !== "#ffffff" &&
            iStyle.fill !== "#000000" &&
            iStyle.fill !== "#FF0000" &&
            iStyle.fill !== "#0000FF" &&
            iStyle.fill !== "#00FF00" &&
            iStyle.fill !== "#FF60AF"
          ) {
            const iFill = currColor.value;
            let strokeColor = iStyle.stroke;
            const iWidth = iStyle.width;
            // 获取勾边宽度，没有或为0，表示没有勾边
            if (iWidth === 0 || !iWidth) {
              strokeColor = null;
            }
            if (!strokeColor) {
              // 勾边色为空，只有填充；无勾边 2-1-1
              newStyle = new Style({
                fill: new Fill({
                  color: iFill,
                }),
              });
            } else if (
              strokeColor &&
              strokeColor !== "#003F98" &&
              strokeColor !== "#FFF000" &&
              strokeColor !== "#009944" &&
              iStyle.fill !== "#004097" &&
              strokeColor !== "#FF0000" &&
              strokeColor !== "#0000FF" &&
              strokeColor !== "#00FF00" &&
              strokeColor !== "#FF60AF"
            ) {
              // 有描边色
              // 有描边色，且不是固有色，替换成当前色（样式：多边形有颜色-当前色，边使用当前色）2-1-2
              // if ( strokeColor && strokeColor !== '#003F98' && strokeColor !== '#FFF000' && strokeColor !== '#009944') { // 有描边色
              newStyle = new Style({
                fill: new Fill({
                  color: iFill,
                }),
                stroke: new Stroke({
                  color: currColor.value,
                  width: iStyle.width ? iStyle.width : 0,
                }),
              });
              // 描边色是固有色，使用固有描边色（样式：多边形有颜色-当前色，边使用固有色）2-1-3
            } else if (
              strokeColor === "#003F98" ||
              strokeColor === "#FFF000" ||
              strokeColor === "#009944" ||
              strokeColor === "#004097" ||
              strokeColor === "#FF0000" ||
              strokeColor === "#0000FF" ||
              strokeColor === "#00FF00" ||
              strokeColor === "#FF60AF"
            ) {
              newStyle = new Style({
                fill: new Fill({
                  color: iFill,
                }),
                stroke: new Stroke({
                  color: strokeColor,
                  width: iStyle.width ? iStyle.width : 0,
                }),
              });
            }
          } else {
            // 填充色为固有色 2-2
            const iFill = iStyle.fill;
            let strokeColor = iStyle.stroke;
            const iWidth = iStyle.width;
            // 获取勾边宽度，没有或为0，表示没有勾边
            if (iWidth === 0 || !iWidth) {
              strokeColor = null;
            }
            if (!strokeColor) {
              // 勾边色为空，只有填充；无勾边 2-2-1
              newStyle = new Style({
                fill: new Fill({
                  color: iFill,
                }),
              });
            } else if (
              strokeColor &&
              strokeColor !== "#003F98" &&
              strokeColor !== "#FFF000" &&
              strokeColor !== "#009944" &&
              strokeColor !== "#004097" &&
              strokeColor !== "#FF0000" &&
              strokeColor !== "#0000FF" &&
              strokeColor !== "#00FF00" &&
              strokeColor !== "#FF60AF"
            ) {
              // 有描边色
              // （样式：多边形有颜色-固有色，边使用当前色）2-2-2
              newStyle = new Style({
                fill: new Fill({
                  color: iFill,
                }),
                stroke: new Stroke({
                  color: currColor.value,
                  width: iStyle.width ? iStyle.width : 0,
                }),
              });
              // （样式：多边形有颜色-固有色，描边使用固有色）2-2-3
            } else if (
              strokeColor === "#003F98" ||
              strokeColor === "#FFF000" ||
              strokeColor === "#009944" ||
              strokeColor === "#004097" ||
              strokeColor === "#FF0000" ||
              strokeColor === "#0000FF" ||
              strokeColor === "#00FF00" ||
              strokeColor === "#FF60AF"
            ) {
              newStyle = new Style({
                fill: new Fill({
                  color: iFill,
                }),
                stroke: new Stroke({
                  color: strokeColor,
                  width: iStyle.width ? iStyle.width : 0,
                }),
              });
            }
          }
          currPlot.value.style = null;
        }
        // 设置虚线--如果设置了style.lineDash参数需要设置虚线
        if (iStyle.lineDash) {
          const iStroke = newStyle.getStroke();
          iStroke.setLineDash(iStyle.lineDash);
        }
        // 属性添加到Featrue
        iFeature.setStyle(newStyle);
      }
      if (iType === "linestring") {
        iGeom = new LineString(iData);
        iFeature = new Feature(iGeom);
        // 需要添加控制点属性--待添加
        iFeature.set("gid", gID);
        iFeature.set("type", "PLOT");
        // 属性创建

        let strokeColor = iStyle.stroke;
        if (!strokeColor) {
          // 勾边色为空，设置为当前色
          strokeColor = currColor.value;
        }
        // 有勾边色，设置多边形为描边样式，边的颜色如果不是固有色，替换成当前色： B-1
        if (
          strokeColor &&
          strokeColor !== "#003F98" &&
          strokeColor !== "#FFF000" &&
          strokeColor !== "#009944" &&
          strokeColor !== "#004097" &&
          strokeColor !== "#FF0000" &&
          strokeColor !== "#0000FF" &&
          strokeColor !== "#00FF00" &&
          strokeColor !== "#FF60AF" &&
          strokeColor !== "#FFFFFF" &&
          strokeColor !== "#000000" &&
          strokeColor !== "#DEB887"
        ) {
          // 有描边色
          newStyle = new Style({
            stroke: new Stroke({
              color: currColor.value,
              width: iStyle.width ? iStyle.width : 2,
            }),
          });
        } else if (
          strokeColor === "#003F98" ||
          strokeColor === "#FFF000" ||
          strokeColor === "#009944" ||
          strokeColor === "#004097" ||
          strokeColor === "#FF0000" ||
          strokeColor === "#0000FF" ||
          strokeColor === "#00FF00" ||
          strokeColor === "#FF60AF" ||
          strokeColor === "#FFFFFF" ||
          strokeColor === "#000000" ||
          strokeColor === "#DEB887"
        ) {
          // B-2 勾边为固有色，勾边色保持不变！
          newStyle = new Style({
            stroke: new Stroke({
              color: strokeColor,
              width: iStyle.width ? iStyle.width : 2,
            }),
          });
        }

        // 设置虚线--如果设置了style.lineDash参数需要设置虚线
        if (iStyle.lineDash) {
          console.log(iType);
          const iStroke = newStyle.getStroke();
          iStroke.setLineDash(iStyle.lineDash);
        }
        // 属性添加到Featrue
        iFeature.setStyle(newStyle);
        // 设置图形样式信息--保存数据用！-- icon和dire及mult方式只需要颜色就可以了，不需要使用样式！
        currPlot.value.style = null;
      }
      if (iType === "point") {
        iGeom = new Point(iData[0]);
        iFeature = new Feature(iGeom);
        iFeature.set("gid", gID);
        iFeature.set("type", "PLOT");
        let txtRot;
        if (iStyle.rotate) {
          txtRot = iStyle.rotate;
        } else {
          txtRot = 0;
        }
        // 创建样式
        newStyle = new Style({
          text: new Text({
            // 位置
            textAlign: "left", // 'left', 'right', 'center', 'end' or 'start'.
            // 基准线
            textBaseline: "middle", // 'bottom', 'top', 'middle', 'alphabetic', 'hanging', 'ideographic'.
            // 文字样式
            font: iStyle.font, // 默认格式 'normal 14px 微软雅黑',
            // font: 'normal' + x + 'px 微软雅黑',
            // 文本内容
            text: iStyle.txt,
            scale: iData[1][0], // 文字数据信息[[点的地理坐标x， y]，[文字的缩放*，文字的旋转]]
            rotation: txtRot,
            // 文字旋转
            // 文本填充样式（即文字颜色）
            fill: new Fill({ color: "#000000" }),
            stroke: new Stroke({ color: "#FFFFFF", width: 1 }),
          }),
        });
        // 属性添加到Featrue
        iFeature.setStyle(newStyle);
        currPlot.value.style = null;
      }
      // 绘制cyy添加的circle
      if (iType === "circle") {
        // 获得两个控制点
        const cp1 = iData[0];
        const cp2 = iData[1];
        // 求两个点的距离(半径)--可能需要进行坐标转换，转换到3857，计算长度。（坐标转换）
        const r = plot.CalLengthOfTwoPoints(cp1, cp2);
        // 绘制圆--new Circle(center, opt_radius)
        iGeom = new geoCircle(cp1, r); // 生成圆
        iFeature = new Feature(iGeom); // 生成feature
        // 需要添加控制点属性--待添加
        iFeature.set("gid", gID);
        iFeature.set("type", "PLOT");
        // 属性创建
        if (iStyle.fill === "none" || !iStyle.fill) {
          // 没有填充颜色-1
          let strokeColor = iStyle.stroke;
          if (!strokeColor) {
            // 勾边色为空，设置为当前色
            strokeColor = currColor.value;
          }
          // 有勾边色，设置多边形为描边样式，边的颜色如果不是固有色，替换成当前色： B-1
          if (
            strokeColor &&
            strokeColor !== "#003F98" &&
            strokeColor !== "#FFF000" &&
            strokeColor !== "#009944" &&
            strokeColor !== "#004097" &&
            strokeColor !== "#FF0000" &&
            strokeColor !== "#0000FF" &&
            strokeColor !== "#00FF00" &&
            strokeColor !== "#FF60AF"
          ) {
            // 有描边色
            newStyle = new Style({
              fill: new Fill({
                color: "rgba(0,0,0,0)",
              }),
              stroke: new Stroke({
                color: currColor.value,
                width: iStyle.width ? iStyle.width : 0,
              }),
            });
          } else if (
            strokeColor === "#003F98" ||
            strokeColor === "#FFF000" ||
            strokeColor === "#009944" ||
            strokeColor === "#004097" ||
            strokeColor === "#FF0000" ||
            strokeColor === "#0000FF" ||
            strokeColor === "#00FF00" ||
            strokeColor === "#FF60AF"
          ) {
            // B-2 勾边为固有色，勾边色保持不变！
            newStyle = new Style({
              fill: new Fill({
                color: "rgba(0,0,0,0)",
              }),
              stroke: new Stroke({
                color: strokeColor,
                width: iStyle.width ? iStyle.width : 0,
              }),
            });
          }
          currPlot.value.style = null;
        } else {
          // 多边形有填充色-2
          // 多边形有填充色，非固有色。使用当前颜色2-1
          if (
            iStyle.fill !== "#003F98" &&
            iStyle.fill !== "#FFF000" &&
            iStyle.fill !== "#009944" &&
            iStyle.fill !== "#004097" &&
            iStyle.fill !== "#FF0000" &&
            iStyle.fill !== "#0000FF" &&
            iStyle.fill !== "#00FF00" &&
            iStyle.fill !== "#FF60AF"
          ) {
            const iFill = currColor.value;
            let strokeColor = iStyle.stroke;
            const iWidth = iStyle.width;
            // 获取勾边宽度，没有或为0，表示没有勾边
            if (iWidth === 0 || !iWidth) {
              strokeColor = null;
            }
            if (!strokeColor) {
              // 勾边色为空，只有填充；无勾边 2-1-1
              newStyle = new Style({
                fill: new Fill({
                  color: iFill,
                }),
              });
            } else if (
              strokeColor &&
              strokeColor !== "#003F98" &&
              strokeColor !== "#FFF000" &&
              strokeColor !== "#009944" &&
              iStyle.fill !== "#004097" &&
              strokeColor !== "#FF0000" &&
              strokeColor !== "#0000FF" &&
              strokeColor !== "#00FF00" &&
              strokeColor !== "#FF60AF"
            ) {
              // 有描边色
              // 有描边色，且不是固有色，替换成当前色（样式：多边形有颜色-当前色，边使用当前色）2-1-2
              // if ( strokeColor && strokeColor !== '#003F98' && strokeColor !== '#FFF000' && strokeColor !== '#009944') { // 有描边色
              newStyle = new Style({
                fill: new Fill({
                  color: iFill,
                }),
                stroke: new Stroke({
                  color: currColor.value,
                  width: iStyle.width ? iStyle.width : 0,
                }),
              });
              // 描边色是固有色，使用固有描边色（样式：多边形有颜色-当前色，边使用固有色）2-1-3
            } else if (
              strokeColor === "#003F98" ||
              strokeColor === "#FFF000" ||
              strokeColor === "#009944" ||
              strokeColor === "#004097" ||
              strokeColor === "#FF0000" ||
              strokeColor === "#0000FF" ||
              strokeColor === "#00FF00" ||
              strokeColor === "#FF60AF"
            ) {
              newStyle = new Style({
                fill: new Fill({
                  color: iFill,
                }),
                stroke: new Stroke({
                  color: strokeColor,
                  width: iStyle.width ? iStyle.width : 0,
                }),
              });
            }
          } else {
            // 填充色为固有色 2-2
            const iFill = iStyle.fill;
            let strokeColor = iStyle.stroke;
            const iWidth = iStyle.width;
            // 获取勾边宽度，没有或为0，表示没有勾边
            if (iWidth === 0 || !iWidth) {
              strokeColor = null;
            }
            if (!strokeColor) {
              // 勾边色为空，只有填充；无勾边 2-2-1
              newStyle = new Style({
                fill: new Fill({
                  color: iFill,
                }),
              });
            } else if (
              strokeColor &&
              strokeColor !== "#003F98" &&
              strokeColor !== "#FFF000" &&
              strokeColor !== "#009944" &&
              strokeColor !== "#004097" &&
              strokeColor !== "#FF0000" &&
              strokeColor !== "#0000FF" &&
              strokeColor !== "#00FF00" &&
              strokeColor !== "#FF60AF"
            ) {
              // 有描边色
              // （样式：多边形有颜色-固有色，边使用当前色）2-2-2
              newStyle = new Style({
                fill: new Fill({
                  color: iFill,
                }),
                stroke: new Stroke({
                  color: currColor.value,
                  width: iStyle.width ? iStyle.width : 0,
                }),
              });
              // （样式：多边形有颜色-固有色，描边使用固有色）2-2-3
            } else if (
              strokeColor === "#003F98" ||
              strokeColor === "#FFF000" ||
              strokeColor === "#009944" ||
              strokeColor === "#004097" ||
              strokeColor === "#FF0000" ||
              strokeColor === "#0000FF" ||
              strokeColor === "#00FF00" ||
              strokeColor === "#FF60AF"
            ) {
              newStyle = new Style({
                fill: new Fill({
                  color: iFill,
                }),
                stroke: new Stroke({
                  color: strokeColor,
                  width: iStyle.width ? iStyle.width : 0,
                }),
              });
            }
          }
          currPlot.value.style = null;
        }

        // 设置虚线--如果设置了style.lineDash参数需要设置虚线
        if (iStyle.lineDash) {
          const iStroke = newStyle.getStroke();
          iStroke.setLineDash(iStyle.lineDash);
        }
        // 属性添加到Featrue
        iFeature.setStyle(newStyle);
      }
      plottingLayer.getSource().addFeature(iFeature);
    }
  }
};

// 数据需要保存到数据库，记录信息添加了数据归属和时间戳，
// 创建currPlotAddUserTime 修改updateTimestamp 删除"delPlot()"（删除军标按钮）面板中的确定 的地方需要添加此方法
const plotRecordUpdate = (plotJson, updateType) => {
  if (!plotJson) return;
  const oAction = {};
  const iType = updateType.toLowerCase();
  if (iType === "c") {
    // add
    oAction.action = "C";
    oAction.plot_id = plotFileID.value;
    oAction.element_id = plotJson.id;
    oAction.creator = iUser.value; // plotJson['owner'] // iUser.value
    oAction.ctime = plotJson.TS;
    oAction.modifier = iUser.value; // plotJson['owner'] // iUser.value
    oAction.mtime = plotJson.TS;
    oAction.content = JSON.parse(JSON.stringify(plotJson));
  } else if (iType === "u") {
    // update
    oAction.action = "U";
    oAction.plot_id = plotFileID.value;
    oAction.element_id = plotJson.id;
    oAction.creator = plotJson.owner;
    oAction.modifier = iUser.value; // plotJson['owner'] // iUser.value
    oAction.mtime = plotJson.TS;
    oAction.content = JSON.parse(JSON.stringify(plotJson));
  } else if (iType === "d") {
    // del
    oAction.action = "D"; // 如果一个军标创建后修改又删除了--如何处理，给数据库？
    oAction.plot_id = plotFileID.value;
    oAction.element_id = plotJson;
    oAction.modifier = iUser.value; // plotJson['owner'] // iUser.value
    oAction.mtime = new Date().getTime(); // plotJson['TS']
    oAction.content = JSON.parse(JSON.stringify(plotJson)); // 是个数组--包含删除的所有军标数据
  }

  // 把数据写入plotRecord[]  -- 数据载入时，将所有数据遍历，查看是否有对应军标，有的修改删除，没有的不处理（新建除外）
  if (plotRecord.value[oAction.element_id]) {
    oAction.createUser = plotRecord.value[oAction.element_id].createUser;
    oAction.createTime = plotRecord.value[oAction.element_id].createTime;
    plotRecord.value[oAction.element_id] = oAction;
  } else {
    plotRecord.value[oAction.element_id] = oAction;
  }
  if (recordLen.value >= Object.keys(plotRecord.value).length) {
    // 需要调用保存数据方法，将plotRecord数据写入数据库；这里没有plotID需要调用外部方法，完成后清除plotRecord数组
  }
};

// 添加用户和时间戳
const currPlotAddUserTime = () => {
  currPlot.value.owner = iUser.value;
  currPlot.value.TS = new Date().getTime();
  plotRecordUpdate(currPlot.value, "C");
};

// 地图图例去重
const updateLegendList = (newPlotData) => {
  // 唯一性索引
  const mapdata = new Map();
  // 拷贝标绘数据
  const copyPlotData = JSON.parse(JSON.stringify(newPlotData));
  // 实际的数据 - 图例的数据 - 原始数据
  const iconJson = [];
  const groupList = Object.keys(iconGroupJSON.value);
  groupList.forEach((item) => {
    if (item !== "show") {
      iconJson.push(...iconGroupJSON.value[item]);
    }
  });
  if (copyPlotData.length > 0) {
    iconJson.forEach((standardIcon) => {
      copyPlotData.forEach((plotIcon) => {
        const index =
          plotIcon.id.split("").length -
          plotIcon.id.split("").findLastIndex((i) => i === "_");
        const idName = plotIcon.id.substr(0, index);
        const realName = plotIcon.name;
        if (standardIcon.key === idName || standardIcon.key === realName) {
          mapdata.set(standardIcon.key, plotIcon);
        }
      });
    });
  }
  if (drawing.value.图例.内容.length > 0) {
    const newArr = [...mapdata.values()];
    drawing.value.图例.内容.forEach((item, index) => {
      const isExist = newArr.some((oldval) => oldval.id === item.id);
      if (!isExist) {
        drawing.value.图例.内容.splice(index, 1);
      }
    });
    newArr.forEach((ele) => {
      const isExist = drawing.value.图例.内容.some(
        (oldval) => oldval.id === ele.id
      );
      if (!isExist) drawing.value.图例.内容.push(ele);
    });
  } else {
    drawing.value.图例.内容 = [...mapdata.values()];
  }
};

/**
 * @description 保存标绘数据
 * @param null
 * @return
 */
const getSaveData = () => {
  for (let i = 0; i < xData.value.length; i++) {
    // 标绘中的文字元素换行处理
    const xId = xData.value[i].id;
    const iType = xId.substr(0, 4);
    if (iType === "text") {
      const iText = xData.value[i].style.text;
      xData.value[i].style.text = iText.replace(/\n/g, "\\n");
    }
  }
  // 重新组织保存的数据
  const iUnit = mapUnit.value;
  const sRCS = conf.value.RCS;
  const plotData = {
    fileID: plotFileID.value,
    unit: iUnit,
    RCS: sRCS,
    strokeWidth: strokeWidth.value,
    data: xData.value,
  };
  return plotData;
};

/**
 *  des: 地图标绘信息发生变化（添加或者删除）
 *  1. 重新获取当前的地图数据信息并赋值到drawing里面
 *  2. 将图例进行更新
 */
const plotUpdate = (data) => {
  const newPlotData = getSaveData();
  updateLegendList(newPlotData.data);
};

/*
 * parseGeometry
 * 生成绘制方法所需的geometry数据;drawend生成GeometryCollection对象使用！
 * 参数cData(coordinate point data)通过绘制方法生成的点数据, 如：{geoType:整体类型，geoData[{gid:123,type:LineSting,data[],style:{}},...]}
 * 返回：geometries数组，每个元素是一个geometry对象（线，面等），如：[polygon,linestring,...]
 */
const parseGeometry = (cData) => {
  let geometry = null;
  const geometries = []; // 保存每个绘制图形的对象
  if (cData.geoType === "GeometryCollection") {
    for (let i = 0; i < cData.geoData.length; i++) {
      const iType = cData.geoData[i].type;
      // 获取返回结果查看是否有属性
      let iStyle = cData.geoData[i].style;
      if (!iStyle) {
        iStyle = {
          fill: null,
          stroke: currColor.value,
          width: "2px",
        };
      }
      // 根据类型设置数据（目前只有Polygon，LineString，Text）
      switch (iType.toLowerCase()) {
        case "linestring": // LineString
          geometry = new LineString(cData.geoData[i].data);
          geometries.push(geometry);
          break;
        case "polygon": // Polygon
          geometry = new Polygon(cData.geoData[i].data);
          geometries.push(geometry);
          break;
        case "circle":
          const cp1 = cData.geoData[i].data[0];
          const cp2 = cData.geoData[i].data[1];
          // 求两个点的距离(半径)--可能需要进行坐标转换，转换到3857，计算长度。（坐标转换）
          const r = plot.CalLengthOfTwoPoints(cp1, cp2);
          geometry = new geoCircle(cp1, r);
          geometries.push(geometry);
          break;
        default:
      } // end switch
    } // end for
    return geometries;
  } else {
    console.log("123");
  }
};

const addInteraction = () => {
  let value = iType.value;
  let iMaxPoints = null;
  if (!value) return; // 没有绘制样式时推出(null就返回)
  if (value.length < 4) return; // 长度不满足要求不做处理
  const drawType = iType.value.substr(0, 4).toLowerCase();
  if (
    drawType === "icon" ||
    drawType === "dire" ||
    drawType === "mult" ||
    drawType === "ddir"
  ) {
    // 三种vector类型处理
    value = drawType;
  }
  if (value !== "none") {
    // None
    let geometryFunction;
    if (value === "text") {
      value = "Point";
    } else if (value === "unionRange") {
      // Square
      value = "Circle";
    } else if (value === "Square") {
      // Square
      value = "Circle";
      geometryFunction = createRegularPolygon(4);
    } else if (value === "rect") {
      // Box
      value = "Circle";
      geometryFunction = createBox();
    } else if (value === "bbox") {
      // BBox:范围盒创建绘制
      value = "Circle";
      geometryFunction = createBox();
    } else if (value === "icon") {
      // 绘制军标
      value = "Circle";
      geometryFunction = (coordinates, geometry) => {
        // 去除错误提示
        if (coordinates.length > 1) endPlotting();
        // 将地理坐标转换成屏幕坐标
        const screenCoord = map.getPixelFromCoordinate(coordinates[0]);
        // 获得生成的军标图元{geoType：'xxx', geodata:[{},{}]}
        plot_geometries.value = getFeature(
          [screenCoord],
          "icon",
          iActType.value,
          map
        );
        // 设置军标的线宽
        setSVGStyle(plot_geometries.value, strokeWidth.value, currColor.value);
        geom2Featrue(plot_geometries.value); // 将军标绘制到标绘层（样式处理）

        // 将当前军标写入，军标数组！
        currPlotAddUserTime(); // 添加用户和时间戳
        xData.value.push(JSON.parse(JSON.stringify(currPlot.value)));
        plotUpdate({
          act: "add",
          data: iType.value,
        });
        endPlotting();
      };
    } else if (value === "dire") {
      // 绘制定向军标，有方向
      const drawType = value;
      value = "Circle";
      geometryFunction = (coordinates, geometry) => {
        // 将地理坐标转换成屏幕坐标
        if (coordinates.length < 2) return; // 定向军标需要两个控制点（原点和方向）
        const cp1 = map.getPixelFromCoordinate(coordinates[0]); // 控制点1：中心点
        const cp2 = map.getPixelFromCoordinate(coordinates[1]); // 控制点2：方向点
        // 军标数据获取
        plot_geometries.value = getFeature(
          [cp1, cp2],
          drawType,
          iActType.value,
          map
        );
        const geometryList = parseGeometry(plot_geometries.value); // 返回生成的geometry如：[polygon,linestring,...] 提供给下面生成geometrycollection
        // 绘制临时显示的军标
        if (!geometry) {
          geometry = new GeometryCollection(geometryList);
        } else {
          geometry.setGeometries(geometryList);
        }
        return geometry;
      };
    } else if (value === "ddir") {
      // 绘制定向军标，svg根据方向有两个
      const drawType = value;
      value = "Circle";
      geometryFunction = (coordinates, geometry) => {
        // 将地理坐标转换成屏幕坐标
        if (coordinates.length < 2) return; // 定向军标需要两个控制点（原点和方向）
        const cp1 = map.getPixelFromCoordinate(coordinates[0]); // 控制点1：中心点
        const cp2 = map.getPixelFromCoordinate(coordinates[1]); // 控制点2：方向点
        // console.log(cp1,cp2)
        // 军标数据获取
        plot_geometries.value = getFeature(
          [cp1, cp2],
          drawType,
          iActType.value,
          map
        );
        const geometryList = parseGeometry(plot_geometries.value); // 返回生成的geometry如：[polygon,linestring,...] 提供给下面生成geometrycollection
        // 绘制临时显示的军标
        // console.log(geometryList)
        if (!geometry) {
          geometry = new GeometryCollection(geometryList);
        } else {
          geometry.setGeometries(geometryList);
        }
        return geometry;
      };
    } else if (value === "Star") {
      // Star,启动到前面去
      value = "Circle";
      geometryFunction = function (coordinates, geometry) {
        const center = coordinates[0];
        const last = coordinates[1];
        const dx = center[0] - last[0];
        const dy = center[1] - last[1];
        const radius = Math.sqrt(dx * dx + dy * dy);
        const rotation = Math.atan2(dy, dx);
        const newCoordinates = [];
        const numPoints = 12;
        for (let i = 0; i < numPoints; ++i) {
          const angle = rotation + (i * 2 * Math.PI) / numPoints;
          const fraction = i % 2 === 0 ? 1 : 0.5;
          const offsetX = radius * fraction * Math.cos(angle);
          const offsetY = radius * fraction * Math.sin(angle);
          newCoordinates.push([center[0] + offsetX, center[1] + offsetY]);
        }
        newCoordinates.push(newCoordinates[0].slice());
        if (!geometry) {
          geometry = new Polygon([newCoordinates]);
        } else {
          geometry.setCoordinates([newCoordinates]);
        }
        return geometry;
      };
    } else if (value === "mult") {
      // 线条箭头类(SingleLineArrow:简单线箭头>,SingleSolidArrow：getSSArrowPnts)
      // 获取绘制方法名称
      let funName = iType.value.split("_")[1];
      // 获取绘制点数_名称最后一位
      const maxPnt = funName.substr(funName.length - 1, 1);
      // 最后一位为数字，需要设置绘制控制点数量，修改方法名称
      if (!isNaN(maxPnt)) {
        iMaxPoints = parseInt(maxPnt);
        funName = funName.substr(0, funName.length - 1);
      }
      if (!funName) return;
      // 绘制方式，用来控制绘制点数量
      value = "LineString";
      // 查看方法是否存在，不存在退出！
      const func = plot.getFunc(funName);
      // 方法不存在退出绘制！
      if (!func) return;
      // 开始绘制箭头类形军标
      geometryFunction = (coordinates, geometry) => {
        // 返回绘制箭头所需的--几何元素
        plot_geometries.value = func(coordinates); // 返回组成军标的所有数据[geoType:xx,geoData:[{图元1},{图元2}...];但是图元信息不全
        const geometryList = parseGeometry(plot_geometries.value); // 返回生成的geometry如：[polygon,linestring,...] 提供给下面生成geometrycollection
        // 所有绘制plot均视为GeometryCollection
        if (!geometry) {
          geometry = new GeometryCollection(geometryList);
        } else {
          geometry.setGeometries(geometryList);
        }
        // 绘制控制点记录
        currPlot.value.cp = coordinates; // 只要cp为有用数据，其他为“脏”数据
        // 绘制临时图像-drawend中写入军标绘制层
        return geometry;
      };
    } else if (value === "infoBox") {
      // 提示或注释框
      value = "LineString";
      iMaxPoints = 3;
      geometryFunction = function (coordinates, geometry) {
        const newCoordinates = [];
        const iBbox = [];
        if (coordinates.length === 1) {
          newCoordinates.push(coordinates[0], coordinates[0], coordinates[0]);
        } else if (coordinates.length === 2) {
          iBbox.push(
            coordinates[0][0] <= coordinates[1][0]
              ? coordinates[0][0]
              : coordinates[1][0]
          );
          iBbox.push(
            coordinates[0][1] <= coordinates[1][1]
              ? coordinates[0][1]
              : coordinates[1][1]
          );
          iBbox.push(
            coordinates[0][0] > coordinates[1][0]
              ? coordinates[0][0]
              : coordinates[1][0]
          );
          iBbox.push(
            coordinates[0][1] > coordinates[1][1]
              ? coordinates[0][1]
              : coordinates[1][1]
          );
          newCoordinates.push(
            [iBbox[0], iBbox[1]],
            [iBbox[0], iBbox[3]],
            [iBbox[2], iBbox[3]],
            [iBbox[2], iBbox[1]],
            [iBbox[0], iBbox[1]]
          );
        } else if (coordinates.length >= 3) {
          iBbox.push(
            coordinates[0][0] <= coordinates[1][0]
              ? coordinates[0][0]
              : coordinates[1][0]
          );
          iBbox.push(
            coordinates[0][1] <= coordinates[1][1]
              ? coordinates[0][1]
              : coordinates[1][1]
          );
          iBbox.push(
            coordinates[0][0] > coordinates[1][0]
              ? coordinates[0][0]
              : coordinates[1][0]
          );
          iBbox.push(
            coordinates[0][1] > coordinates[1][1]
              ? coordinates[0][1]
              : coordinates[1][1]
          );
          const pt3rd = coordinates[2];
          if (iBbox[0] < pt3rd[0] && pt3rd[0] < iBbox[2]) {
            // 在box的x范围内
            if (iBbox[1] < pt3rd[1] && pt3rd[1] < iBbox[3]) {
              // 在box的y范围内
              // 在绘制的盒子box中，不显示小尾巴
              newCoordinates.push(
                [iBbox[0], iBbox[1]],
                [iBbox[0], iBbox[3]],
                [iBbox[2], iBbox[3]],
                [iBbox[2], iBbox[1]],
                [iBbox[0], iBbox[1]]
              );
            } else if (pt3rd[1] > iBbox[3]) {
              // 小尾巴在box上边
              const p1 = [iBbox[0], iBbox[3]];
              const p2 = [iBbox[2], iBbox[3]];
              const d = Math.sqrt(
                (p1[0] - p2[0]) * (p1[0] - p2[0]) +
                  (p1[1] - p2[1]) * (p1[1] - p2[1])
              );
              const tithe = d / 10;
              const pp1 = [p1[0] + tithe * 4, p1[1]];
              const pp2 = [p1[0] + tithe * 6, p1[1]];
              newCoordinates.push(
                [iBbox[0], iBbox[1]],
                [iBbox[0], iBbox[3]],
                pp1,
                pt3rd,
                pp2,
                [iBbox[2], iBbox[3]],
                [iBbox[2], iBbox[1]],
                [iBbox[0], iBbox[1]]
              );
            } else if (pt3rd[1] < iBbox[1]) {
              // 小尾巴在box下边
              const p1 = [iBbox[0], iBbox[1]]; // 左下角坐标
              const p2 = [iBbox[2], iBbox[1]]; // 右下角坐标
              const d = Math.sqrt(
                (p1[0] - p2[0]) * (p1[0] - p2[0]) +
                  (p1[1] - p2[1]) * (p1[1] - p2[1])
              );
              const tithe = d / 10;
              const pp1 = [p1[0] + tithe * 4, p1[1]];
              const pp2 = [p1[0] + tithe * 6, p1[1]];
              // 注意最有一个封口线的顺序（顺时针pp2, pt3rd, pp1, ）
              newCoordinates.push(
                [iBbox[0], iBbox[1]],
                [iBbox[0], iBbox[3]],
                [iBbox[2], iBbox[3]],
                [iBbox[2], iBbox[1]],
                pp2,
                pt3rd,
                pp1,
                [iBbox[0], iBbox[1]]
              );
            }
          } else if (iBbox[1] < pt3rd[1] < iBbox[3]) {
            // 在box的y范围内
            if (pt3rd[0] > iBbox[2]) {
              // 小尾巴在box右边
              const p1 = [iBbox[2], iBbox[3]]; // 右下角坐标
              const p2 = [iBbox[2], iBbox[1]]; // 右下角坐标
              const d = Math.sqrt(
                (p1[0] - p2[0]) * (p1[0] - p2[0]) +
                  (p1[1] - p2[1]) * (p1[1] - p2[1])
              );
              const tithe = d / 10;
              const pp1 = [p1[0], p1[1] - tithe * 4];
              const pp2 = [p1[0], p1[1] - tithe * 6];
              // 注意最有一个封口线的顺序（顺时针pp2, pt3rd, pp1, ）
              newCoordinates.push(
                [iBbox[0], iBbox[1]],
                [iBbox[0], iBbox[3]],
                [iBbox[2], iBbox[3]],
                pp1,
                pt3rd,
                pp2,
                [iBbox[2], iBbox[1]],
                [iBbox[0], iBbox[1]]
              );
            } else if (pt3rd[0] < iBbox[0]) {
              // 小尾巴在box左边
              const p1 = [iBbox[0], iBbox[1]]; // 右下角坐标
              const p2 = [iBbox[0], iBbox[3]]; // 右下角坐标
              const d = Math.sqrt(
                (p1[0] - p2[0]) * (p1[0] - p2[0]) +
                  (p1[1] - p2[1]) * (p1[1] - p2[1])
              );
              const tithe = d / 10;
              const pp1 = [p1[0], p1[1] + tithe * 4];
              const pp2 = [p1[0], p1[1] + tithe * 6];
              // 注意最有一个封口线的顺序（顺时针pp2, pt3rd, pp1）
              newCoordinates.push(
                [iBbox[0], iBbox[1]],
                pp1,
                pt3rd,
                pp2,
                [iBbox[0], iBbox[3]],
                [iBbox[2], iBbox[3]],
                [iBbox[2], iBbox[1]],
                [iBbox[0], iBbox[1]]
              );
            } else {
              // 鼠标在四角，不显示小尾巴
              newCoordinates.push(
                [iBbox[0], iBbox[1]],
                [iBbox[0], iBbox[3]],
                [iBbox[2], iBbox[3]],
                [iBbox[2], iBbox[1]],
                [iBbox[0], iBbox[1]]
              );
            }
          }
        }

        if (!geometry) {
          geometry = new Polygon([newCoordinates]);
        } else {
          geometry.setCoordinates([newCoordinates]);
        }
        return geometry;
      };
    } else if (value === "flagPlus") {
      // 可添加数量的旗帜
      value = "Circle";
      geometryFunction = function (coordinates, geometry) {
        const newCoordinates = [];
        if (coordinates.length === 1) {
          newCoordinates.push(coordinates[0], coordinates[0]);
        } else if (coordinates.length === 2) {
          const cp1 = coordinates[0];
          const cp2 = coordinates[1];
          const xDist = Math.abs(cp2[0] - cp1[0]);
          const yDist = Math.abs(cp2[1] - cp1[1]);
          const d = xDist > yDist ? xDist : yDist;
          const dUnit = d / 5;
          const p2 = [cp1[0], cp1[1] + d];
          const p3 = [cp1[0] + 5 * dUnit, cp1[1] + 5 * dUnit];
          const p4 = [cp1[0] + 5 * dUnit, cp1[1] + 3 * dUnit];
          const p5 = [cp1[0], cp1[1] + dUnit * 3];
          newCoordinates.push(cp1, p2, p3, p4, p5, cp1);
        }
        if (!geometry) {
          geometry = new Polygon([newCoordinates]);
        } else {
          geometry.setCoordinates([newCoordinates]);
        }
        return geometry;
      };
    } else if (value === "triangle") {
      // 三角形，实现牵引线
      value = "LineString";
      iMaxPoints = 3;
      geometryFunction = function (coordinates, geometry) {
        const newCoordinates = [];
        if (coordinates.length === 1) {
          newCoordinates.push(coordinates[0], coordinates[0], coordinates[0]);
        } else if (coordinates.length === 2) {
          newCoordinates.push(
            coordinates[0],
            coordinates[1],
            coordinates[1],
            coordinates[0]
          );
        } else if (coordinates.length >= 3) {
          newCoordinates.push(
            coordinates[0],
            coordinates[1],
            coordinates[2],
            coordinates[0]
          );
        }
        if (!geometry) {
          geometry = new Polygon([newCoordinates]);
        } else {
          geometry.setCoordinates([newCoordinates]);
        }
        // console.log(geometry)
        return geometry;
      };
    } else if (value === "plott") {
      // 圆型图标
      value = "Point";
      iMaxPoints = 1;
    }
    iDraw = new Draw({
      type: value,
      maxPoints: iMaxPoints,
      geometryFunction: geometryFunction,
    });
    map.addInteraction(iDraw);
  }
  // let listener
  // 绘制开始事件
  iDraw.on("drawstart", (evt) => {
    console.log(evt);
  });
  // 绘制结束事件
  iDraw.on("drawend", (evt) => {
    const iType = iActType.value.substr(0, 4);
    const idStr = iActType.value + "_" + new Date().valueOf();
    const iPlott = evt.feature;
    // 处理基本图形数据
    if (
      iType === "Line" ||
      iType === "Squa" ||
      iType === "rect" ||
      iType === "Star" ||
      iType === "Circ" ||
      iType === "info" ||
      iType === "flag" ||
      iType === "tria" ||
      iType === "unio"
    ) {
      iPlott.set("gid", idStr);
      iPlott.set("type", "PLOT");
      iPlott.setStyle(
        new Style({
          fill: new Fill({
            color: "rgba(255,0,0,0)",
          }),
          stroke: new Stroke({
            // ol.style.Stroke
            color: currColor.value,
            width: strokeWidth.value,
          }),
        })
      );

      plottingLayer.getSource().addFeature(iPlott);
      // 设置图形样式信息--保存数据用！
      setCurrPlotStyle("rgba(0,0,0,0)", currColor.value, strokeWidth.value);
      const iGeometry = iPlott.getGeometry();
      const iGeoType = iGeometry.getType();
      if (iGeoType === "Polygon") {
        currPlot.value.id = idStr;
        currPlot.value.name = iGeoType; // 类型为多边形 还是iType？
        currPlot.value.cp = iGeometry.getCoordinates(); // ctrlpoint控制点，包含中心点
        currPlot.value.scale = 1;
        currPlot.value.rotate = 0;
        currPlot.value.color = currColor.value; // 颜色（样式需要更详细些，可能还会有虚线！）
        currPlot.value.unit = null; // 基础多边形不需要次属性
        currPlot.value.attach = null; // 关联文字数组！
        currPlot.value.boxWH = null; // polygon不需要此数据
      } else if (iGeoType === "LineString") {
        currPlot.value.id = idStr;
        currPlot.value.name = iGeoType; // 类型为多边形 还是iType？
        currPlot.value.cp = iGeometry.getCoordinates(); // ctrlpoint控制点，包含中心点
        currPlot.value.scale = 1;
        currPlot.value.rotate = 0;
        currPlot.value.color = currColor.value; // 颜色（样式需要更详细些，可能还会有虚线！）
        currPlot.value.unit = null; // 基础多边形不需要次属性
        currPlot.value.attach = null; // 关联文字数组！
        currPlot.value.boxWH = null; // LineStrion不需要此数据
      } else if (iGeoType === "Circle") {
        const cp1 = iGeometry.getCenter();
        const r = iGeometry.getRadius();
        const cp2 = [cp1[0] + r, cp1[1]];
        currPlot.value.id = idStr;
        currPlot.value.name = iGeoType; // 类型为多边形 还是iType？
        // 将圆的控制点2从保存半径，变成控制点2 （圆心x+加班经， 圆心y）
        currPlot.value.cp = [cp1, cp2];
        currPlot.value.scale = 1;
        currPlot.value.rotate = 0;
        currPlot.value.color = currColor.value; // 颜色（样式需要更详细些，可能还会有虚线！）
        currPlot.value.unit = null; // 基础多边形不需要次属性
        currPlot.value.attach = null; // 关联文字数组！
        currPlot.value.boxWH = null; // circle不需要此数据
      }
    } else if (iType === "dire") {
      // 军标SVG类型绘制 【iType === 'icon' || 此类型直接在点击时处理了，这里不再处理】
      // 将标绘图形加入标绘层
      // 设置军标的线宽
      setSVGStyle(plot_geometries.value, strokeWidth.value, currColor.value);
      // 默认参数是this.plot_geometries
      geom2Featrue();
    } else if (iType === "ddir") {
      // 根据两个控制点，计算调用的svg文件
      const cPnts = currPlot.value.cp;
      const dx = cPnts[1][0] - cPnts[0][0]; // 水平方向差值
      const dy = cPnts[1][1] - cPnts[0][1]; // 垂直方向差值
      const xTail = currPlot.value.name.substr(
        currPlot.value.name.length - 1,
        1
      );
      if (dy >= 0) {
        // 保持当前的svg文件
        // 如果是b的要转成普通svg，然后调用绘制--改下
        if (xTail === "@") {
          currPlot.value.name = currPlot.value.name.substr(
            0,
            currPlot.value.name.length - 1
          );
          plot_geometries.value = createSVGPlot(currPlot.value); // 设置军标的线宽已放到此方法中
        } else {
          plot_geometries.value = createSVGPlot(currPlot.value); // setSVGStyle设置军标的线宽已放到此方法中
        }
      } else {
        if (xTail === "@") {
          plot_geometries.value = createSVGPlot(currPlot.value); // 设置军标的线宽已放到此方法中
        } else {
          currPlot.value.name = currPlot.value.name + "@";
          plot_geometries.value = createSVGPlot(currPlot.value); // 设置军标的线宽已放到此方法中
        }
      }
    } else if (iType === "mult") {
      // 箭头类型
      // 箭头处理，和SVG方式应该一致
      // 需要补全图元缺失部分
      const iStyle = {
        fill: "none", // currColor.value,
        stroke: currColor.value,
        width: strokeWidth.value, // 2
      };
      for (let i = 0; i < plot_geometries.value.geoData.length; i++) {
        plot_geometries.value.geoData[i].gid = idStr;
        plot_geometries.value.geoData[i].style = JSON.parse(
          JSON.stringify(iStyle)
        );
      }

      // 实心箭头和虚线箭头样式设置（需要调整-见下面）
      if (
        iActType.value === "mult_getSSArrowPnts" ||
        iActType.value === "mult_dashArrowPnts" ||
        iActType.value === "mult_pathArrowPnts" ||
        iActType.value === "mult_dashPathArrowPnts"
      ) {
        plot_geometries.value.geoData[0].style.fill = currColor.value;
        plot_geometries.value.geoData[0].style.width = 0;
      }

      // 新添加的带轮线（箭头要填充！）
      if (iActType.value === "mult_getCyyLine") {
        // 组成图形的顺序[箭头多边形，主曲线，辅助曲线，圆轮xn]
        plot_geometries.value.geoData[0].style.fill = currColor.value;
        plot_geometries.value.geoData[0].style.width = 0;
        plot_geometries.value.geoData[2].style.stroke = "#000000";
        plot_geometries.value.geoData[2].color = "#000000";
        if (currPlot.value.cp.length === 2) {
          const cp1 = currPlot.value.cp[0];
          const cp2 = currPlot.value.cp[1];
          const midPnt = [(cp1[0] + cp2[0]) / 2, (cp1[1] + cp2[1]) / 2];
          currPlot.value.cp.splice(1, 0, midPnt);
        }
      }
      // 摩托化行进
      if (iActType.value === "mult_getMotorLine") {
        // 组成图形的顺序[箭头多边形，主曲线，辅助曲线，圆轮xn]
        plot_geometries.value.geoData[0].style.fill = currColor.value;
        plot_geometries.value.geoData[0].style.width = 0;
        if (currPlot.value.cp.length === 2) {
          const cp1 = currPlot.value.cp[0];
          const cp2 = currPlot.value.cp[1];
          const midPnt = [(cp1[0] + cp2[0]) / 2, (cp1[1] + cp2[1]) / 2];
          currPlot.value.cp.splice(1, 0, midPnt);
        }
      }
      // 伴随线
      if (iActType.value === "mult_getFollowLine") {
        // 组成图形的顺序[箭头多边形，主曲线，辅助曲线，圆轮xn]
        plot_geometries.value.geoData[0].style.fill = currColor.value;
        plot_geometries.value.geoData[0].style.width = 0;
        plot_geometries.value.geoData[2].style.stroke = "#DEB887";
        if (currPlot.value.cp.length === 2) {
          const cp1 = currPlot.value.cp[0];
          const cp2 = currPlot.value.cp[1];
          const midPnt = [(cp1[0] + cp2[0]) / 2, (cp1[1] + cp2[1]) / 2];
          currPlot.value.cp.splice(1, 0, midPnt);
        }
      }

      // 虚线的处理
      if (
        iActType.value === "mult_dashArrowPnts" ||
        iActType.value === "mult_dashPathArrowPnts"
      ) {
        plot_geometries.value.geoData[1].style.lineDash = [20, 10];
      }
      // 将标绘图形加入标绘层
      geom2Featrue();
      // 当前会信息补全
      currPlot.value.id = idStr;
      currPlot.value.name = iActType.value; // 类型为多边形 还是iType？
      // currPlot.value.cp = // ctrlpoint控制点，包含中心点 已经在绘制时更新
      currPlot.value.scale = 1;
      currPlot.value.rotate = 0;
      currPlot.value.color = currColor.value; // 颜色（样式需要更详细些，可能还会有虚线！）
      currPlot.value.unit = null; // 基础多边形不需要次属性
      currPlot.value.attach = null; // 关联文字数组！
      currPlot.value.boxWH = null; // mult不需要此数据
    } else if (iType === "text") {
      // 组id - 文字以text-开头； 军标内文字待定--应该是个控制点；gid和军标本身类型相同
      iPlott.set("gid", idStr);
      iPlott.set("type", "PLOT"); // 类型为标绘
      // 设置样式
      iPlott.setStyle(
        new Style({
          text: new Text({
            // 位置
            textAlign: "left", // 'left', 'right', 'center', 'end' or 'start'.
            // 基准线
            textBaseline: "middle", // 'bottom', 'top', 'middle', 'alphabetic', 'hanging', 'ideographic'.
            font: "normal 12px 微软雅黑",
            text: "请添加文字",
            fill: new Fill({
              color: "#000000",
            }),
          }),
        })
      );
      plottingLayer.getSource().addFeature(iPlott);
      // 设置图形样式信息--保存数据用！
      setCurrPlotStyle(
        "#000000",
        null,
        0,
        null,
        "请添加文字",
        "normal 12px 微软雅黑"
      );
      // 设置样式;参数 Fill填充色或文字颜色； Stroke边色； Width边框； LineDash虚线样式； TEXT文本内容； Font字体样式，如： ‘normal 12px 微软雅黑’

      // 设置要保存的信息
      const iGeometry = iPlott.getGeometry();
      // 需要获得文字的第二个控制点（new）
      const cp2WH = getTxtCPntAndWH(
        iGeometry.getCoordinates(),
        12,
        "请添加文字"
      );
      const iGeoType = iGeometry.getType();
      if (iGeoType === "Point") {
        currPlot.value.id = idStr;
        currPlot.value.name = iGeoType; // 类型为多边形 还是iType？
        currPlot.value.cp = cp2WH.cp;
        currPlot.value.boxWH = cp2WH.boxWH; // 用来保存文字像素尺寸
        currPlot.value.scale = 1;
        currPlot.value.rotate = 0;
        currPlot.value.color = currColor.value; // 颜色（样式需要更详细些，可能还会有虚线！）
        currPlot.value.unit = null; // 基础多边形不需要此属性
        currPlot.value.attach = null;
      }
    } else if (iType === "bbox") {
      const iGeometry = iPlott.getGeometry();
      const cPnts = iGeometry.getCoordinates();
      updateBBox(cPnts);
    }
    // 标绘停止
    const sPlotType = iActType.value; // 为事件发送
    endPlotting();
    // 添加用户和时间戳(改为调用方法)
    currPlotAddUserTime(); // 添加用户和时间戳
    // 将当前绘制军标数据（currPlot）写入列表中！--> xData
    const dCache = JSON.parse(JSON.stringify(currPlot.value));
    xData.value.push(dCache);
    console.log(xData.value);
    // 需要添加数据库方法！！
    // 发送事件，告知军标绘制完成
    plotUpdate({ act: "add", data: sPlotType });
  });
};

// 更新BBox数据
// 通过参数提供的坐标点数组，计算新的范围盒，更新并调整到正确显示
const updateBBox = (ctrlPntLs) => {
  let boundingBox = null;
  boundingBox = getMinMax(ctrlPntLs);
  bbox.value = boundingBox;
  // 更新范围盒显示
  // 参数：boxCoord = [minx, miny, maxx, maxy] 范围盒;默认 参数bbox.value
  boxZoom();
};

// 框选放大功能（用来匹配鼠标拖拽产生的范围）
// 参数：boxCoord = [minx, miny, maxx, maxy] 范围盒
const boxZoom = (boxCoord = bbox.value) => {
  if (!boxCoord) return;
  const iView = map.getView(); // 获取当前地图的view
  const iSize = map.getSize(); // 获取地图的尺寸
  // 获取用户框定的坐标范围
  const extent = boxCoord; // [0,0,10000,10000] [[0,0],[10000,0],[10000,10000],[0,10000]]
  const resolution = iView.getResolutionForExtent(extent, iSize); //  以提供范围和尺寸，获取分辨率
  var center = olExtent.getCenter(extent);
  // 设置缩放时动画效果
  iView.animate({
    resolution: resolution, // 动画结束时视图的分辨率。如果zoom还提供，则将忽略此选项。
    center: center, // 动画结束时视图的中心
  });
};

const initPlottingLayer = () => {
  const defStyle = new Style({
    fill: new Fill({
      color: "rgba(255,0,0,0.4)",
    }),
    stroke: new Stroke({
      color: "#e21e0a",
      width: strokeWidth.value, // 2
    }),
    image: new CircleStyle({
      radius: 5,
      fill: new Fill({
        color: "#ff0000",
      }),
    }),
    text: new Text({
      fill: new Fill({
        // 文字填充色
        color: "#ff0000",
      }),
      stroke: new Stroke({
        // 文字边界宽度与颜色
        color: "rgba(255,0,0,0)",
        width: 1,
      }),
    }),
  });

  plottingLayer = new VectorLayer({
    source: new VectorSource(), // ol.source.Vector 用来保存标绘
    wrapX: false,
    style: defStyle,
  });
  map.addLayer(plottingLayer);
};

onMounted(() => {
  initMap();
  initPlottingLayer();
});
</script>
<template>
  <div id="map"></div>
  <div class="btns">
    <el-button type="primary" @click="lineClick">虚线箭头</el-button>
  </div>
</template>
<style lang="scss" scoped>
#map {
  width: 100%;
  height: 100vh;
}

.btns {
  position: absolute;
  left: 40px;
  top: 20px;
}
</style>
